package com.ailight.smart.api.client;

import com.ailight.smart.api.entity.dto.LightGearDTO;
import com.ailight.smart.api.enums.ModelEnums;
import com.ailight.smart.api.enums.OperationTypeEnums;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Promise;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

@Component
@Slf4j
public class Esp8266NettyClient {
    // 配置参数
    @Value("${esp8266.ip}")
    private String espIp;
    @Value("${esp8266.port}")
    private int espPort;
    @Value("${esp8266.reconnectDelay}")
    private int reconnectDelay;
    @Value("${esp8266.dataTimeout}")
    private int dataTimeout; // 数据接收超时时间(秒)

    // 状态管理
    private final AtomicBoolean isConnected = new AtomicBoolean(Boolean.FALSE);
    private EventLoopGroup workerGroup;
    private Bootstrap bootstrap;
    private Channel channel;
    private DataHandler dataHandler;

    /**
     * 存储当前状态标志位
     */
    private final Map<String, ModelEnums> map = new ConcurrentHashMap<>();


    public Esp8266NettyClient() {
        initNettyClient();
        // 初始化为自动模式
        map.put("state", ModelEnums.AUTO_MODE);
    }

    private void initNettyClient() {
        workerGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap()
                .group(workerGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .option(ChannelOption.SO_KEEPALIVE, true) // 启用TCP keepalive
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        // 每次连接创建新的DataHandler
                        dataHandler = new DataHandler();
                        ch.pipeline()
                                .addLast(new StringDecoder(StandardCharsets.UTF_8)) // 字节转字符串
                                .addLast(new StringEncoder(StandardCharsets.UTF_8)) // 字符串转字节
                                .addLast(new ConnectionHandler())  // 连接管理
                                .addLast(dataHandler);             // 数据处理器
                    }
                });
        startConnection();
    }

    /**
     * 启动连接（异步）
     */
    private void startConnection() {
        workerGroup.schedule(this::connect, 1, TimeUnit.SECONDS);
    }

    private void connect() {
        if (isConnected.get()) return;


        bootstrap.connect(espIp, espPort).addListener((ChannelFuture future) -> {
            if (future.isSuccess()) {
                channel = future.channel();
                isConnected.set(Boolean.TRUE);
                log.info("成功连接到ESP8266设备");

                // 初始化DataHandler的EventLoop
                if (dataHandler != null) {
                    dataHandler.init(channel.eventLoop());
                }
            } else {
                Throwable cause = future.cause();
                String causeMsg = cause != null ? cause.getMessage() : "未知原因";
                log.warn("连接失败 (), {}秒后重试... 原因: {}",
                        reconnectDelay / 1000, causeMsg);
                scheduleReconnect();
            }
        });
    }

    private void scheduleReconnect() {
        workerGroup.schedule(this::connect, reconnectDelay, TimeUnit.MILLISECONDS);
    }

    /**
     * 发送命令（线程安全）
     */
    public void sendCommand(OperationTypeEnums operationTypeEnums) {
        // 记录状态标志位
        this.setStateMap(operationTypeEnums.getModelEnums());
        try {
            sendMsg(operationTypeEnums.getOpeName());
        } catch (Exception e) {
            log.error("发送命令异常", e);
        }
    }

    private void sendMsg(String msg) {
        if (!isConnected.get() || channel == null) {
            log.warn("发送失败：设备未连接");
            return;
        }

        //添加发送结果监听
        ChannelFuture future = channel.writeAndFlush(msg);
        future.addListener(f -> {
            if (f.isSuccess()) {
                log.info("命令发送成功: {}", msg);
            } else {
                log.error("命令发送失败", f.cause());
            }
        });
    }

    /**
     * 获取设备当前数据（同步方法）
     */
    public LightGearDTO getCurrentData() {
        if (!isConnected.get() || channel == null) {
            log.warn("设备未连接，无法获取数据");
            return new LightGearDTO(0, 0);
        }

        if (dataHandler == null) {
            log.warn("DataHandler未初始化");
            return new LightGearDTO(0, 0);
        }

        try {
            // 1. 重置数据处理器状态
            dataHandler.reset();
            // 3. 等待数据返回（同步阻塞）
            return dataHandler.waitForData(dataTimeout, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("等待数据被中断");
            return new LightGearDTO(0, 0);
        } catch (TimeoutException e) {
            log.warn("获取数据超时，{}秒内未收到响应", dataTimeout);
            return new LightGearDTO(0, 0);
        } catch (IllegalStateException e) {
            log.error("DataHandler未初始化: {}", e.getMessage());
            return new LightGearDTO(0, 0);
        }
    }

    @PreDestroy
    public void shutdown() {
        if (channel != null) {
            channel.close();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        log.info("ESP8266客户端已关闭");
    }

    private void setStateMap(ModelEnums modelEnums) {
        map.put("state", modelEnums);
    }

    public ModelEnums getStateMap() {
        if (!isConnected.get() || channel == null) {
            throw new RuntimeException("设备未连接");
        }
        return map.get("state");
    }

    public boolean isConnected() {
        return isConnected.get();
    }

    /**
     * 连接状态处理器 - 增强重连机制
     */
    private class ConnectionHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            log.info("连接已建立");
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            log.warn("连接已断开");
            isConnected.set(Boolean.FALSE);
            channel = null;
            dataHandler = null; // 清除当前DataHandler
            scheduleReconnect();
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            log.error("通信异常: {}", cause.getMessage());
            isConnected.set(Boolean.FALSE);
            channel = null;
            dataHandler = null; // 清除当前DataHandler
            ctx.close();
        }
    }

    /**
     * 数据处理器（处理设备返回的数据）
     */
    private static final class DataHandler extends SimpleChannelInboundHandler<String> {
        private EventExecutor executor;
        private Promise<LightGearDTO> dataPromise;
        private boolean isWaiting = false;

        /**
         * 初始化EventExecutor
         */
        public void init(EventExecutor executor) {
            this.executor = executor;
            this.dataPromise = new DefaultPromise<>(executor);
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) {
            log.info("收到设备数据: {}", msg);

            if (isWaiting) {
                try {
                    // 解析数据格式: $light:123#,$gear:3#
                    int light = 0;
                    int gear = 0;

                    if (msg.contains("$light:")) {
                        int start = msg.indexOf("$light:") + 7;
                        int end = msg.indexOf("#", start);
                        if (end > start) {
                            light = Integer.parseInt(msg.substring(start, end));
                        }
                    }

                    if (msg.contains("$gear:")) {
                        int start = msg.indexOf("$gear:") + 6;
                        int end = msg.indexOf("#", start);
                        if (end > start) {
                            gear = Integer.parseInt(msg.substring(start, end));
                        }
                    }

                    // 完成Promise
                    dataPromise.setSuccess(new LightGearDTO(light, gear));
                    isWaiting = false;
                } catch (Exception e) {
                    log.error("数据解析失败: {}", msg, e);
                    dataPromise.setFailure(e);
                    isWaiting = false;
                }
            }
        }

        public void reset() {
            if (executor == null) {
                throw new IllegalStateException("DataHandler 未初始化");
            }

            // 取消之前的Promise（如果存在）
            if (dataPromise != null && !dataPromise.isDone()) {
                dataPromise.cancel(true);
            }

            // 创建新的Promise
            dataPromise = new DefaultPromise<>(executor);
            isWaiting = true;
        }

        public LightGearDTO waitForData(long timeout, TimeUnit unit)
                throws InterruptedException, TimeoutException {

            if (dataPromise == null) {
                throw new IllegalStateException("DataHandler 未初始化");
            }

            // 等待Promise完成
            if (!dataPromise.await(timeout, unit)) {
                throw new TimeoutException("Data not received within timeout");
            }

            if (!dataPromise.isSuccess()) {
                throw new RuntimeException("Failed to get data", dataPromise.cause());
            }

            return dataPromise.getNow();
        }
    }
}